"""
ConnLLM提供者基类
实现基础的LLM提供者功能和能力管理
"""
from abc import ABC, abstractmethod
import logging
import time
from typing import Dict, List, Optional, Any, Generator, Type, Tuple, Set

# 设置日志
logger = logging.getLogger("connllm.provider")

class BaseProvider:
	"""LLM提供商基础实现，使用组合而非继承"""
	
	def __init__(self, config: Dict[str, Any]):
		"""
		初始化基础提供商
		
		Args:
			config: 配置字典
		"""
		# 导入组件类
		from .config import ConfigManager
		from .capability import CapabilityManager
		from .retry import RetryHandler
		from .tokens import TokenCounter, CostCalculator
		
		# 使用组合而非继承
		self.config_manager = ConfigManager(config)
		
		# 提取常用配置，方便访问
		self.provider_type = self.config_manager.get_provider_type()
		self.model = self.config_manager.get_model()
		
		# 验证配置是否有效
		self.config_manager.validate()
		
		# 初始化核心组件
		self.capability_manager = CapabilityManager(self)
		
		# 可选组件，通过条件初始化
		self.http_client = self._create_http_client() if self._needs_http_client() else None
		
		# 核心功能组件
		retry_settings = self.config_manager.get_retry_settings()
		self.retry_handler = RetryHandler(
			max_retries=retry_settings.get('max_retries', 3),
			retry_delay=retry_settings.get('retry_delay', 1.0),
			retry_strategy=retry_settings.get('retry_strategy', 'exponential')
		)
		
		self.token_counter = TokenCounter(self.provider_type, self.model)
		self.cost_calculator = CostCalculator(self.provider_type, self.model)
		
		# 初始化能力
		self._init_capabilities()
		
	def _needs_http_client(self) -> bool:
		"""
		判断是否需要HTTP客户端
		
		Returns:
			是否需要HTTP客户端
		"""
		return True  # 默认需要，子类可以重写
		
	def _create_http_client(self) -> Any:
		"""
		创建HTTP客户端
		
		Returns:
			HTTP客户端实例
		"""
		from .http import HTTPClient
		
		# 根据提供商类型确定基础URL
		api_base = self.config_manager.get('api_base')
		if not api_base:
			# 尝试从常量获取默认URL
			try:
				from ..core.constants import API_BASE_URLS
				api_base = API_BASE_URLS.get(self.provider_type)
			except ImportError:
				api_base = None
		
		# 创建HTTP客户端
		return HTTPClient(
			base_url=api_base,
			headers=self._get_default_headers(),
			timeout=self.config_manager.get('timeout', 60),
			proxy=self.config_manager.get('proxy')
		)
	
	def _get_default_headers(self) -> Dict[str, str]:
		"""
		获取默认HTTP头
		
		Returns:
			默认HTTP头字典
		"""
		headers = {
			'Content-Type': 'application/json'
		}
		
		# 如果是远程提供商，添加认证头
		if self.config_manager.is_remote_provider():
			api_key = self.config_manager.get('api_key')
			if api_key:
				# 根据提供商类型设置不同的认证头
				if self.provider_type == 'anthropic':
					headers['x-api-key'] = api_key
				elif self.provider_type in ['openai', 'openrouter', 'moonshot']:
					headers['Authorization'] = f"Bearer {api_key}"
		
		return headers
		
	def _init_capabilities(self) -> None:
		"""
		初始化能力，子类应重写此方法
		
		子类应在此方法中注册支持的能力
		"""
		pass
	
	def complete(self, messages: List[Dict[str, Any]], stream: bool = False) -> str:
		"""
		获取LLM完成结果
		
		Args:
			messages: 消息列表
			stream: 是否流式响应
			
		Returns:
			完成的文本
		"""
		if stream:
			return "".join(self.complete_stream(messages))
			
		# 使用重试处理器包装API调用
		response = self.retry_handler.execute(
			self._complete_internal,
			args=(messages,)
		)
		
		# 计算token和成本
		input_tokens, output_tokens = self.token_counter.extract_from_response(response)
		cost = self.cost_calculator.calculate(input_tokens, output_tokens)
		
		if input_tokens > 0 or output_tokens > 0:
			logger.debug(
				f"Token使用量({self.provider_type}/{self.model}): "
				f"输入={input_tokens}, 输出={output_tokens}, "
				f"成本=${cost:.6f}"
			)
		
		# 提取文本内容
		return self._extract_text_from_response(response)
		
	def complete_stream(self, messages: List[Dict[str, Any]]) -> Generator[str, None, None]:
		"""
		获取LLM流式完成结果
		
		Args:
			messages: 消息列表
			
		Returns:
			流式响应生成器
		"""
		# 检查是否有流式能力
		if self.capability_manager.has('streaming'):
			streaming = self.capability_manager.get('streaming')
			yield from streaming.stream_response(messages)
		else:
			# 后备实现：使用普通完成并逐字符返回
			content = self._complete_internal(messages)
			text = self._extract_text_from_response(content)
			for char in text:
				yield char
				
	def _extract_text_from_response(self, response: Any) -> str:
		"""
		从响应中提取文本
		
		Args:
			response: 响应数据
			
		Returns:
			提取的文本
		"""
		# 如果响应已经是字符串，直接返回
		if isinstance(response, str):
			return response
			
		# 如果响应不是字典，尝试转换为字符串
		if not isinstance(response, dict):
			return str(response)
			
		# Anthropic风格（Claude 3）
		if "content" in response:
			if isinstance(response["content"], str):
				return response["content"]
			elif isinstance(response["content"], list):
				# 提取text类型的内容
				text_parts = []
				for content_item in response["content"]:
					if content_item.get("type") == "text":
						text_parts.append(content_item.get("text", ""))
				return "".join(text_parts)
				
		# OpenAI风格
		if "choices" in response and len(response["choices"]) > 0:
			choice = response["choices"][0]
			
			# GPT-4/3.5 风格
			if "message" in choice and "content" in choice["message"]:
				return choice["message"]["content"]
				
			# GPT-3 风格
			elif "text" in choice:
				return choice["text"]
				
		# Moonshot风格
		if "response" in response:
			return response["response"]
			
		# 其他格式
		if "text" in response:
			return response["text"]
			
		# 尝试JSON序列化作为最后手段
		try:
			import json
			return json.dumps(response, ensure_ascii=False)
		except:
			pass
			
		# 无法提取，返回空字符串
		logger.warning(f"无法从响应中提取文本: {type(response)}")
		return ""
		
	def extract_thinking(self, response: Dict[str, Any]) -> Optional[str]:
		"""
		从响应中提取思考过程（如Claude Thinking）
		
		Args:
			response: 响应数据
			
		Returns:
			思考过程文本，如果不存在则返回None
		"""
		if not isinstance(response, dict):
			return None
			
		# Claude 3.7 Thinking
		if (self.provider_type == "anthropic" or 
		   (self.provider_type == "openrouter" and "claude" in self.model)) and ":thinking" in self.model:
			if "content" in response and isinstance(response["content"], list):
				for content_item in response["content"]:
					if content_item.get("type") == "thinking":
						return content_item.get("text", "")
		
		return None
		
	def filter_chat_args(self, *args, **kwargs) -> tuple:
		"""
		过滤和处理API调用参数
		
		Args:
			*args: 位置参数
			**kwargs: 关键字参数
			
		Returns:
			处理后的(args, kwargs)元组
		"""
		return args, kwargs
		
	def calculate_tokens(self, response: Dict[str, Any]) -> Tuple[int, int]:
		"""
		计算输入和输出令牌数
		
		Args:
			response: 响应数据
			
		Returns:
			(输入令牌数, 输出令牌数)元组
		"""
		return self.token_counter.extract_from_response(response)
		
	def calculate_cost(self, input_tokens: int, output_tokens: int) -> float:
		"""
		计算API调用成本
		
		Args:
			input_tokens: 输入令牌数
			output_tokens: 输出令牌数
			
		Returns:
			成本（美元）
		"""
		return self.cost_calculator.calculate(input_tokens, output_tokens)
		
	@abstractmethod
	def _complete_internal(self, messages: List[Dict[str, Any]]) -> Any:
		"""
		内部完成方法，子类必须实现
		
		Args:
			messages: 消息列表
			
		Returns:
			API原始响应
		"""
		pass


# 兼容层适配器
class LegacyProviderAdapter:
	"""旧API兼容适配器，用于适配旧代码到新架构"""
	
	def __init__(self, new_provider: BaseProvider):
		"""
		初始化适配器
		
		Args:
			new_provider: 新架构下的提供商实例
		"""
		self.provider = new_provider
		
		# 从新实例提取常用属性，确保兼容性
		self.provider_type = getattr(new_provider, 'provider_type', None)
		self.model = getattr(new_provider, 'model', None)
		
		# 如果新实例有config_manager，提取原始配置
		if hasattr(new_provider, 'config_manager'):
			self.config = new_provider.config_manager.raw_config
		else:
			self.config = {}
			
		# 提取其他常用属性
		common_attrs = [
			'max_retries', 'retry_delay', 'temperature', 
			'max_tokens', 'timeout', 'api_key', 'api_base'
		]
		
		for attr in common_attrs:
			# 首先尝试从实例直接获取
			if hasattr(new_provider, attr):
				setattr(self, attr, getattr(new_provider, attr))
			# 然后尝试从config_manager获取
			elif hasattr(new_provider, 'config_manager'):
				setattr(self, attr, new_provider.config_manager.get(attr))
		
	def complete(self, messages: List[Dict[str, str]], stream: bool = False) -> str:
		"""
		获取LLM完成
		
		Args:
			messages: 消息列表
			stream: 是否使用流式响应
			
		Returns:
			完成的文本
		"""
		return self.provider.complete(messages, stream)
	
	def complete_stream(self, messages: List[Dict[str, str]]) -> Generator[str, None, None]:
		"""
		获取LLM流式完成
		
		Args:
			messages: 消息列表
			
		Returns:
			流式响应生成器
		"""
		yield from self.provider.complete_stream(messages)
		
	def __getattr__(self, name):
		"""
		代理其他方法和属性到内部provider实例
		
		Args:
			name: 属性或方法名
			
		Returns:
			对应的属性或方法
			
		Raises:
			AttributeError: 如果属性不存在
		"""
		if hasattr(self.provider, name):
			return getattr(self.provider, name)
		raise AttributeError(f"{self.__class__.__name__}对象没有属性'{name}'")


# 兼容层函数
def create_provider_from_new_architecture(provider_class: Type, config: Dict[str, Any]) -> Any:
	"""
	从新架构创建提供商实例，并适配为旧接口
	
	Args:
		provider_class: 新架构下的提供商类
		config: 配置字典
		
	Returns:
		适配后的提供商实例
	"""
	# 创建新架构实例
	new_instance = provider_class(config)
	
	# 如果是旧接口的子类（继承自不同的基类），创建适配器
	from ..core.provider import LLMProvider
	if not isinstance(new_instance, LLMProvider):
		return LegacyProviderAdapter(new_instance)
		
	# 否则直接返回
	return new_instance
